package com.woniuxy.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.annotation.Validate;
import com.woniuxy.dto.MenusDto;
import com.woniuxy.dto.UserRelatedDto.UserDto;
import com.woniuxy.dto.UserRelatedDto.UserTableDetails;
import com.woniuxy.dto.UserRelatedDto.UserTableDto;
import com.woniuxy.dto.commonDto.BaseDto;
import com.woniuxy.entity.RoleTable;
import com.woniuxy.entity.UserRole;
import com.woniuxy.entity.UserTable;
import com.woniuxy.enums.CodeEnum;
import com.woniuxy.exception.ActiveCodeException;
import com.woniuxy.exception.PawnRoleException;
import com.woniuxy.exception.PawnUserException;
import com.woniuxy.mapper.UserTableMapper;
import com.woniuxy.param.*;
import com.woniuxy.param.UserRelatedParam.SaveUserParam;
import com.woniuxy.param.UserRelatedParam.SaveUserRoleParam;
import com.woniuxy.param.UserRelatedParam.UpdateUserParam;
import com.woniuxy.param.UserRelatedParam.UserPageAndByKeyParam;
import com.woniuxy.service.RoleTableService;
import com.woniuxy.service.UserRoleService;
import com.woniuxy.service.UserTableService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.util.DateUtil;
import com.woniuxy.util.PageMysqlUtil;
import com.woniuxy.util.WoniuBeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zcx, ftl, gr, rhs
 * @since 2021-12-31
 */
@Service
public class UserTableServiceImpl extends ServiceImpl<UserTableMapper, UserTable> implements UserTableService {

    @Resource
    private StringRedisTemplate srt;

    @Resource
    private UserRoleService urs;


    @Resource
    private RoleTableService rts;


    @Resource
    private RedisTemplate<String, List<MenusDto>> rt;

    private ObjectMapper om = new ObjectMapper();

    @Override
    public UserTableDto findUserById(Integer userId) throws JsonProcessingException {

        String userJson = srt.opsForValue().get("user:info:id" + userId);
        if (null == userJson) {

            UserTable user = getOne(new QueryWrapper<UserTable>().eq("user_del", 0).eq("user_id", userId));
            UserTableDto dto = WoniuBeanUtils.copyObject(user, UserTableDto.class);
            if (null != dto) {
                String json = null;
                json = om.writeValueAsString(dto);
                srt.opsForValue().set("user:info:id" + userId, json, 1, TimeUnit.HOURS);
            }
            return WoniuBeanUtils.copyObject(user, UserTableDto.class);

        } else {
            UserTableDto userTableDto = om.readValue(userJson, UserTableDto.class);
            return userTableDto;

        }

    }

    @Override
    public BaseDto<UserTableDto> listUsers(UserPageAndByKeyParam upp) {

        QueryWrapper<UserTable> query = new QueryWrapper<>();

        //模糊查询3个字段
        if (!StringUtils.isEmpty(upp.getKey())) {
            query.and(wrapper -> wrapper
                    .like("user_account", upp.getKey())
                    .or()
                    .like("user_phone", upp.getKey())
                    .or()
                    .like("user_name", upp.getKey())
            );
        }
        if (!StringUtils.isEmpty(upp.getStatus())) {
            query.eq("user_status", upp.getStatus());
        }


        query.eq("user_del", 0);
        query.orderByDesc("user_id");

         BaseDto<UserTableDto> dto = PageMysqlUtil.pageQuery(UserTableDto.class, this, query, new BaseParam(upp.getIndexPage(), upp.getPageSize()));
//        Page<UserTable> page = page(new Page<>(upp.getIndexPage(), upp.getPageSize()), query);
//
//        PageUsersDto dto = new PageUsersDto();
//        //当前页数
//        dto.setIndexPage(page.getCurrent());
//        //最大数据
//
//        dto.setTotal(page.getTotal());
//
//        //判断是否有上一页
//        dto.setHasPrevious(page.hasPrevious());
//        //判断是否有下一页
//        dto.setHasNext(page.hasNext());
//
//        dto.setList(WoniuBeanUtils.copyList(page.getRecords(), UserTableDto.class));
        return dto;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveUserRole(SaveUserRoleParam arp) {
        UserTable ut = getById(arp.getUserId());

        if (StringUtils.isEmpty(ut))
            throw new PawnUserException(CodeEnum.USER_NULL.getMessage(), CodeEnum.USER_NULL.getCode());


        //清空角色账号的关联角色

        urs.remove(new QueryWrapper<UserRole>().eq("user_id", arp.getUserId()));
        //清空菜单redis
        List<MenusDto> range = rt.opsForValue().get("pawn:menu:userId" + arp.getUserId());
        if (null == range || range.size() <= 0) {

        }
        rt.delete("pawn:menu:userId" + arp.getUserId());




        if (arp.getRoleIds() == null || arp.getRoleIds().size() == 0) return true;

        //获取所有角色的
        List<RoleTable> roles = rts.list(new QueryWrapper<RoleTable>().in("role_id", arp.getRoleIds()));


        if (roles.size() != arp.getRoleIds().size())
            throw new PawnRoleException(CodeEnum.ROLE_ERROR_FIND.getMessage(), CodeEnum.ROLE_ERROR_FIND.getCode());


        List<UserRole> list = arp.getRoleIds().stream().map(
                id -> {
                    UserRole war = new UserRole();
                    war.setRoleId(id);
                    war.setUserId(arp.getUserId());
                    return war;
                }).collect(Collectors.toList());
        return urs.saveBatch(list);
    }


    @ExceptionHandler(Exception.class)
    @Override
    public UserDto SaveUser(SaveUserParam sup) {
        QueryWrapper<UserTable> query = new QueryWrapper<>();

        query.and(wrapper -> wrapper
                .eq("user_account", sup.getUserAccount())
                .or()
                .eq("user_phone", sup.getUserPhone())
        );

        List<UserTable> list = list(query);

        if (null == list || list.size() <= 0) {
            UserTable userTable = WoniuBeanUtils.copyObject(sup, UserTable.class);
            userTable.setUserStatus(0);
            userTable.setUserDel(0);
            //密码加密
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            userTable.setUserPassword(passwordEncoder.encode(userTable.getUserPassword()));
            //设置创建时间

            userTable.setUserCreationtime(DateUtil.parseDateLong(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"));

            if (save(userTable)) {
//                String userJson = srt.opsForValue().get("user:info:id" + userTable.getUserId());
//                if (null != userJson) {
//                    srt.delete("user:info:id" + userTable.getUserId());
//                }
                return WoniuBeanUtils.copyObject(userTable, UserDto.class);
            }

            throw new PawnUserException(CodeEnum.ROLE_SAVE_FAIL.getMessage(), CodeEnum.ROLE_SAVE_FAIL.getCode());

        } else {
            for (UserTable userTable : list) {

                if (sup.getUserAccount().trim().equals(userTable.getUserAccount().trim())) {

                    throw new PawnUserException(CodeEnum.USER_SAVE_FAIL_ACCOUNT.getMessage(), CodeEnum.USER_SAVE_FAIL_ACCOUNT.getCode());
                }

                if (sup.getUserPhone().trim().equals(userTable.getUserPhone().trim())) {

                    throw new PawnUserException(CodeEnum.USER_SAVE_FAIL_PHONE.getMessage(), CodeEnum.USER_SAVE_FAIL_PHONE.getCode());
                }
            }
        }


        return null;
    }

    @ExceptionHandler(Exception.class)
    @Override
    public boolean updateUser(UpdateUserParam uup) {
        UserTable userTable = getById(uup.getUserId());
        if (!userTable.getUserAccount().trim().equals(uup.getUserAccount().trim()))

            throw new PawnUserException(CodeEnum.SER_UPDATE_FAIL_1.getMessage(), CodeEnum.SER_UPDATE_FAIL_1.getCode());

        //先判断电话修改没有
        if (!uup.getUserPhone().equals(userTable.getUserPhone())) {


            UserTable user = getOne(new QueryWrapper<UserTable>().eq("user_phone", uup.getUserPhone()).eq("user_del", 0));
            if (null != user)
                throw new PawnUserException(CodeEnum.USER_SAVE_FAIL_PHONE.getMessage(), CodeEnum.USER_SAVE_FAIL_PHONE.getCode());

        }
        //修改以后再删除redis
        String userJson = srt.opsForValue().get("user:info:id" + userTable.getUserId());
        if (null != userJson) {
            srt.delete("user:info:id" + userTable.getUserId());
        }
        return updateById(WoniuBeanUtils.copyObject(uup, UserTable.class));
    }


    @ExceptionHandler(Exception.class)
    @Override
    public boolean removeUserByIds(List<Integer> ids) {
        List<UserTable> users = listByIds(ids);
        if (ids.size() != users.size())
            throw new PawnUserException(CodeEnum.USER_DELETE_FAIL_1.getMessage(), CodeEnum.USER_DELETE_FAIL_1.getCode());
        for (UserTable user : users) {
            user.setUserDel(1);
        }
        return updateBatchById(users);
    }

    @Validate
    @ExceptionHandler(Exception.class)
    @Override
    public boolean UpdateMyselfParam(UpdateMyselfParam ump) {

        //先判断是不是自己的号
        UserTableDetails ws = ((UserTableDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal());

        if (!ws.getUserPhone().equals(ump.getPhone()))
            throw new ActiveCodeException(CodeEnum.CODE_ERROR_PHONE.getMessage(), CodeEnum.CODE_ERROR_PHONE.getCode());

        UserTable userTable = WoniuBeanUtils.copyObject(ump, UserTable.class);

        if (StringUtils.isEmpty(ump.getUserPhone())) {
            userTable.setUserPhone(ump.getPhone());
        } else {
            //判读电话不能重复,新电话
            if (!ump.getUserPhone().equals(ump.getPhone())) {
                UserTable user = getOne(new QueryWrapper<UserTable>().eq("user_phone", ump.getUserPhone()).eq("user_del", 0));
                if (null != user)
                    throw new PawnUserException(CodeEnum.USER_SAVE_FAIL_PHONE.getMessage(), CodeEnum.USER_SAVE_FAIL_PHONE.getCode());

            }


        }


        //判断密码是否修改，修改以后加密
        if (!StringUtils.isEmpty(ump.getUserPassword())) {
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            userTable.setUserPassword(passwordEncoder.encode(ump.getUserPassword()));
        }


        //修改以后再删除redis
        String userJson = srt.opsForValue().get("user:info:id" + userTable.getUserId());
        if (null != userJson) {
            srt.delete("user:info:id" + userTable.getUserId());
        }

        return updateById(userTable);
    }
}
